// 类型推断
let str: string = "hello ts";
// s = null;

// 接口兼容
interface X {
  a: any;
  b: any;
}
interface Y {
  a: any;
  b: any;
  c: any;
}
let x: X = { a: 1, b: 2 };
let y: Y = { a: 1, b: 2, c: 3 };
// 源类型必须具备目标类型的所有属性
x = y;
// 缺少c属性
// y = x;

// 函数的兼容性
type Handler = (a: number, b: number) => void;
function ref(handler: Handler) {
  return handler;
}
// let handler1 = (a: number, b: number, c: number) => {};
// 源类型<=目标类型 参数个数
let handler1 = (a: number, b: number) => {};
ref(handler1);
// 参数个数要求
let fn = (a: number, b: number) => {};
let optional = (a?: number, b?: number) => {};
let surplus = (...args: number[]) => {};
fn = optional;
fn = surplus;
// 不兼容：要做到兼容,需要关闭编译配置选项
// optional = fn;
// surplus = fn;
// 可以兼容固定参数和可选参数
surplus = fn;
surplus = optional;

// 参数类型兼容
let fn2 = (a: number, b: number) => {};
let fn3 = (a: string, b: string) => {};
// 参数类不一致,所以不兼容
// fn2 = fn3;

let fn4 = (x: X) => {};
let fn5 = (y: Y) => {};
// 参数多的会兼容参数少的
// fn4 = fn5;

// 返回值的类型：目标函数的返回值类型必要要与源函数的返回值类型一致or是它的子类型
var f = () => ({ name: "老李" });
var g = () => ({ name: "老王", age: 30 });
f = g;
// g = f;

// 函数重载：目标函数的参数要多于源函数的参数,才能兼容
function extend(a: number, b: number): number;
function extend(a: number, b: number): any {}

// 枚举类型之间是相互不兼容的
enum m {
  one,
  two,
}
enum n {
  first,
}
// let flag: n = 2;

// 类的兼容性与接口的兼容性相似

// 泛型兼容性
interface getData<T> {}
let data: getData<Number> = {};
let strs: getData<String> = {};
data = strs;
// 泛型函数
let log1 = <T>(x: T): T => {
  console.log(x);
  return x;
};

let log2 = <E>(y: E): E => {
  console.log(y);
  return y;
};

log1 = log2;

// 类型保护
enum Type {
  obj,
  arr,
}
class IsObject {
  toObject() {
    console.log("is object");
  }
  active: string = "active";
}
class IsArray {
  toArray() {
    console.log("hello array");
  }
}

function getType(type: Type) {
  let target = type === Type.obj ? new IsObject() : new IsArray();
  if ((target as IsObject).toObject) {
    (target as IsObject).toObject();
  } else {
    (target as IsArray).toArray();
  }
  return target;
}

// 类型保护机制 instanceof/in/typeof
function getType2(type: Type) {
  let target = type === Type.obj ? new IsObject() : new IsArray();
  if (target instanceof IsObject) {
    target.toObject();
  } else {
    target.toArray();
  }
  return target;
}

// 类型保护机制 in
function getType3(type: Type) {
  let target = type === Type.obj ? new IsObject() : new IsArray();
  if ("active" in target) {
    target.toObject();
  } else {
    target.toArray();
  }
  return target;
}
// isType
function getType4(type: Type) {
  let target = type === Type.obj ? new IsObject() : new IsArray();
  if (isType(target)) {
    target.toObject();
  } else {
    target.toArray();
  }
  return target;
}
getType(Type.obj);

// 通过typeof
function funct(x: string | number) {
  if (typeof x === "string") {
    x.length;
  } else {
    x.toFixed;
  }
}

funct("111");

// 参数 is 类型
function isType(type: IsObject | IsArray): type is IsObject {
  return (type as IsObject).toObject === undefined;
}
